#include <mockcpp/mockcpp.hpp>
#include <testngpp/testngpp.hpp>
#include <Rectangle.h>

USING_MOCKCPP_NS
USING_TESTNGPP_NS

struct TestRectangleData
{
    double length;
    double width;
    double area;
    double perimeter;
    bool isValid;
};

TestRectangleData validData[] =
{
        {2, 3, 6, 10, true},
        {100.0095, 2.002, 200, 204, true},
        {1.23, 2.2, 2.71, 6.86, true},
        {1.22, 2.2, 2.68, 6.84, true},
        {0.01,74.99,  0.75, 150, true}
};

TestRectangleData invalidData[] =
{
        {-5, 3, 0, 0, false},
        {0, 3, 0, 0, false},
        {100.01, 3, 0, 0, false},
        {50, -5, 0, false},
        {50, 0, 0, 0, false},
        {50, 75.00, 0, 0, false},

};

FIXTURE(Rectangle_getArea)
{
    SETUP()
    {
    }
    TEARDOWN()
    {
    }

    void test_getArea(const TestRectangleData & validData)
    {
        const Rectangle rectangle(validData.length, validData.width);
        ASSERT_EQ(validData.area, rectangle.getArea());
    }

    TEST(Area of valid Rectangle should be right)
    {
        for(int i=0; i< sizeof(validData)/sizeof(TestRectangleData);i++)
        {
            test_getArea(validData[i]);
        }
    }

    TEST(Area of invalid Rectangle should be 0)
    {
        for(int i=0; i< sizeof(invalidData)/sizeof(TestRectangleData);i++)
        {
            test_getArea(invalidData[i]);
        }
    }

};

FIXTURE(Rectangle_getPerimeter)
{
    SETUP()
    {
    }
    TEARDOWN()
    {
    }

    void test_getPerimeter(const TestRectangleData & validData)
    {
        const Rectangle rectangle(validData.length, validData.width);
        ASSERT_EQ( validData.perimeter, rectangle.getPerimeter());
    }


    TEST(Perimeter of valid Rectangle should be right)
    {
        for(int i=0; i< sizeof(validData)/sizeof(TestRectangleData);i++)
        {
            test_getPerimeter(validData[i]);
        }
    }

    TEST(Perimeter of invalid Rectangle should be 0)
    {
        for(int i=0; i< sizeof(invalidData)/sizeof(TestRectangleData);i++)
        {
            test_getPerimeter(invalidData[i]);
        }
    }

};

FIXTURE(Rectangle_isValid)
{
     void test_isValid(const TestRectangleData & validData)
    {
        const Rectangle rectangle(validData.length, validData.width);
        ASSERT_EQ(validData.isValid, rectangle.isValid());
    }

    TEST(isValid of valid Rectangle should be true)
    {
        for(int i=0; i< sizeof(validData)/sizeof(TestRectangleData);i++)
        {
            test_isValid(validData[i]);
        }
    }

    TEST(isValid of invalid Rectangle should be false)
    {
        for(int i=0; i< sizeof(invalidData)/sizeof(TestRectangleData);i++)
        {
            test_isValid(invalidData[i]);
        }
    }
};


FIXTURE(Rectangle_changeLength)
{
    void test_changeLengthSuccess(Rectangle& rectangle, const TestRectangleData & data)
    {
       ASSERT_TRUE(rectangle.changeLength(data.length));
       ASSERT_EQ(data.area, rectangle.getArea());
       ASSERT_EQ(data.perimeter, rectangle.getPerimeter());
       ASSERT_TRUE(rectangle.isValid());
    }

    TEST(isValid of valid Rectangle should be true)
    {
        Rectangle rectangle(5,3);

        TestRectangleData changeLengthData[] =
        {
                {2, 3, 6, 10, true},
                {1, 3, 3, 8, true},
                {5.004, 3, 15, 16, true},
                {16, 3, 48, 38, true}
        };
        for(int i=0; i< sizeof(changeLengthData)/sizeof(TestRectangleData);i++)
        {
            test_changeLengthSuccess(rectangle, changeLengthData[i]);
        }
    }

    TEST(isValid of valid Rectangle should be true)
    {
        Rectangle rectangle(5,3);

        double invalidLength[] =
        {-1,0,100.01};


        for(int i=0; i< sizeof(invalidLength)/sizeof(double);i++)
        {
            ASSERT_FALSE(rectangle.changeLength(invalidLength[i]));
        }
    }
};


FIXTURE(Rectangle_changeWidth)
{
    void test_changeWidthSuccess(Rectangle& rectangle, const TestRectangleData & data)
    {
       ASSERT_TRUE(rectangle.changeWidth(data.width));
       ASSERT_EQ(data.area, rectangle.getArea());
       ASSERT_EQ(data.perimeter, rectangle.getPerimeter());
       ASSERT_TRUE(rectangle.isValid());
    }

    TEST(isValid of valid Rectangle should be true)
    {
        Rectangle rectangle(3,5);

        TestRectangleData changeWidthData[] =
        {
                {3,2,  6, 10, true},
                {3,1,  3, 8, true},
                {3, 5.004,  15, 16, true},
                {3, 16, 48, 38, true}
        };
        for(int i=0; i< sizeof(changeWidthData)/sizeof(TestRectangleData);i++)
        {
            test_changeWidthSuccess(rectangle, changeWidthData[i]);
        }
    }

    TEST(isValid of valid Rectangle should be true)
    {
        Rectangle rectangle(5,3);

        double invalidWidth[] =
        {-1,0,75};


        for(int i=0; i< sizeof(invalidWidth)/sizeof(double);i++)
        {
            ASSERT_FALSE(rectangle.changeWidth(invalidWidth[i]));
        }
    }
};



